<?php
declare(strict_types=1);

namespace App\Interface\Pay;

use App\Constants\ErrorCode;
use App\Interface\PaymentStrategyInterface;
use App\Model\BalanceOrder;
use App\Model\Normal;
use App\Model\Order;
use App\Model\RefundLog;
use App\Services\Wechat;
use Carbon\Carbon;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Utils\Str;
use Hyperf\Redis\Redis;
use Trait\ResponseMsg;
use Util\Common;
use Yansongda\Pay\Pay;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Context\ApplicationContext;
use App\Job\CheckPaid;

class WeChatPaymentStrategy implements PaymentStrategyInterface
{

    use ResponseMsg;

    protected array $config;
    private $logger;


    public function __construct()
    {

        $this->config = config('pay');
        $log_name ='wxpay'.date('Y-m-d',time());
        $loggerFactory = container()->get(\Hyperf\Logger\LoggerFactory::class);
        $this->logger = $loggerFactory->get($log_name,'wxpay');
    }

    public function __call($name, $arguments)
    {
        // 处理不存在的实例方法调用
        return '';
    }

    /**支付-通用
     * @param array $data
     * @return mixed
     */
    public function pay(array $data)
    {
        $class = Str::studly($data['type_mode']);
        return $this->$class($data);
    }


    /**根据订单号设置二维码
     * @param $params
     * @return array
     */
    public function qrCode($params)
    {
//        $order = [
//            'out_trade_no' => $params['order_no'] . '-' . $orderModel->version,
//            'description' => $orderModel->title,
//            'amount' => [
//                'total' => $orderModel->real_money,
//            ],
//        ];
//        try {
//            $pay = Pay::wechat($this->config)->scan($order);
//            if(isset($pay['code_url'])){
//                $qrCode = QrCode::create($pay['code_url']);
//                $writer = new PngWriter();
//                $result = $writer->write($qrCode);
//                $pay = $result->getDataUri();
//
//
//            }
//            return array('code' => 200, 'data' => $pay, 'order_info' => $order);
//        } catch (\Exception $e) {
//            return array('code' => ErrorCode::OPTION_ERR, 'message' => $e->getMessage());
//        }

    }


    /**微信回调
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Yansongda\Pay\Exception\ContainerException
     * @throws \Yansongda\Pay\Exception\InvalidParamsException
     */
    public function notify($request)
    {
        $pay = Pay::wechat($this->config);
        $data = $pay->callback($request);
        $this->logger->info('充电支付回调'.json_encode($data));
        $order = Order::where('number',$data['resource']['ciphertext']['out_trade_no'])->first();
        if ($data['summary'] == '支付成功') {
            $params['pay_time'] = date('Y-m-d H:i:s',time());
            $params['out_ord_id'] = $data['resource']['ciphertext']['transaction_id'];
            $order->payMent($params);
            Normal::logger("推送 CheckPaid 任务: {$order->number}", 'order-queue');
            $driver = ApplicationContext::getContainer()->get(DriverFactory::class)->get('check-paid');
            $driver->push(new CheckPaid((string)$order->number), 20);
            return $pay->success();
        }else{
            $order->fail('支付失败');
        }
        $this->logger->info(json_encode($data));
        return false;
    }

    public function balance_notify($request)
    {
        $pay = Pay::wechat($this->config);
        $data = $pay->callback($request);
        $this->logger->info('余额支付回调'.json_encode($data));
        $order = BalanceOrder::where('number',$data['resource']['ciphertext']['out_trade_no'])->first();
        if ($data['summary'] == '支付成功') {
            $order->out_ord_id = $data['resource']['ciphertext']['transaction_id'];
            $order->balanceNotify();
            return $pay->success();
        }else{
            $order->status = Order::STATUS_FAILED;
            $order->save();
        }
        $this->logger->info(json_encode($data));
        return false;
    }


    public function refundNotify($request){
        $pay = Pay::wechat($this->config);
        $data = $pay->callback($request);
        $this->logger->info('充电退款回调'.json_encode($data));
        try{
            if ($data['summary'] == '退款成功') {
                $order = Order::where('number',$data['resource']['ciphertext']['out_trade_no'])->first();
                $refund = RefundLog::where('refund_no',$data['resource']['ciphertext']['out_refund_no'])
                    ->first();
                $refund->return_msg= $data['summary'];
                $refund->status = 1;
                $refund->refund_time = date('Y-m-d H:i:s',time());
                $refund->save();
                $order->return_fee+=$data['resource']['ciphertext']['amount']['refund']?$data['resource']['ciphertext']['amount']['refund']/100:0;
                $order->refund_at = Carbon::now();
                $order->save();
//                if($refund->is_normal == 1){
//                    $params['fee'] = $data['resource']['ciphertext']['amount']['refund']?$data['resource']['ciphertext']['amount']['refund']/100:0;
//                    $order->normalRefundSuccess($params);
//                }
                return $pay->success();
            }else{
                $refund = RefundLog::where('refund_no',$data['resource']['ciphertext']['out_refund_no'])
                    ->first();
                $refund->return_msg= $data['summary'];
                $refund->status = 2;
                $refund->save();
                Normal::logger('error----refund----'.json_encode($data),'order-event');
            }
            return false;
        }catch (\Exception $e){
            $this->logger->info(json_encode($data));
        }
    }


    public function refundBalanceNotify($request){
        $pay = Pay::wechat($this->config);
        $data = $pay->callback($request);
        $this->logger->info('余额退款回调'.json_encode($data));
        try{
            if ($data['summary'] == '退款成功') {
                $order = BalanceOrder::where('number',$data['resource']['ciphertext']['out_trade_no'])->first();
                $refund = RefundLog::where('refund_no',$data['resource']['ciphertext']['out_refund_no'])
                    ->first();
                $order->status = Order::STATUS_REFUNDED;
                $order->return_fee+=$data['resource']['ciphertext']['amount']['refund']?$data['resource']['ciphertext']['amount']['refund']/100:0;
                $order->save();
                $refund->status = 1;
                $refund->refund_time = date('Y-m-d H:i:s',time());
                $refund->save();
                return $pay->success();
            }else{
                $refund = RefundLog::where('refund_no',$data['resource']['ciphertext']['out_refund_no'])
                    ->first();
                $refund->message = $data['summary'];
                $refund->status = 2;
                $refund->save();
            }
            return false;
        }catch (\Exception $e){
            $this->logger->info(json_encode($data));
        }
    }



    public function refund($params)
    {
        $order = [
            'out_trade_no' => $params['number'],
            'out_refund_no' => $params['refund_no'],
            'amount' => [
                'refund' => (int)round(($params['return_fee']*100)),
                'total' => (int)round(($params['fee']*100)),
                'currency' => 'CNY',
            ],
            // '_action' => 'jsapi', // jsapi 退款，默认
            // '_action' => 'app', // app 退款
            // '_action' => 'combine', // 合单退款
            // '_action' => 'h5', // h5 退款
             '_action' => 'mini', // 小程序退款
            // '_action' => 'native', // native 退款
            'notify_url'=>$params['notify_url']
        ];
    //    Normal::logger('退款配置打印-save-' .json_encode($this->config), 'notify-event');
        Normal::logger('退款参数打印-save-' .json_encode($order), 'notify-event');
        return Pay::wechat($this->config)->refund($order);
    }


    /**同步取消微信订单
     * @param string $order_no
     * @return void
     * @throws \Yansongda\Pay\Exception\ContainerException
     * @throws \Yansongda\Pay\Exception\InvalidParamsException
     * @throws \Yansongda\Pay\Exception\ServiceNotFoundException
     */
    public function cancel(string $order_no)
    {
        $order_close = [
            'out_trade_no' => $order_no,
        ];
        Pay::wechat($this->config)->close($order_close);
        return '';
    }



    /**小程序支付
     * @param array $params
     * @return array
     */
    public function miniPay(array $params): array
    {
            $order = [
                'out_trade_no' => $params['number'],
                'description' => $params['description'],
                'amount' => [
                    'total' => $params['amount']*100,
                    'currency' => 'CNY',
                ],
                'payer' => [
                    'openid' => $params['openid'],
                ],
                'notify_url' =>$params['notify_url']
            ];
            return Pay::wechat($this->config)->mini($order)->toArray();
    }

    /**充值余额
     * @param array $params
     * @return array
     */
    public function miniBalance(array $params):array{
        $order = [
            'out_trade_no' => $params['number'],
            'description' => $params['description'],
            'amount' => [
                'total' => $params['amount']*100,
                'currency' => 'CNY',
            ],
            'payer' => [
                'openid' => $params['openid'],
            ],
            'notify_url' =>$params['notify_url']
        ];
        return Pay::wechat($this->config)->mini($order)->toArray();
    }



}
